package com.zt.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zt.annotation.AdminLog;
import com.zt.common.Result;
import com.zt.service.AdminLogService;
import com.zt.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 管理员操作日志切面
 * @author 周明震
 * @date 2025/7/21
 */
@Aspect
@Component
public class AdminLogAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(AdminLogAspect.class);
    
    @Autowired
    private AdminLogService adminLogService;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.zt.annotation.AdminLog)")
    public void adminLogPointcut() {}
    
    /**
     * 环绕通知
     */
    @Around("adminLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 获取注解信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AdminLog adminLogAnnotation = method.getAnnotation(AdminLog.class);

        // 只记录增删改操作，跳过查询操作
        if (adminLogAnnotation.type() == AdminLog.OperationType.QUERY) {
            return joinPoint.proceed();
        }

        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;

        // 获取管理员信息
        Integer adminId = null;
        String adminUsername = "unknown";

        if (request != null) {
            String token = getTokenFromRequest(request);
            if (token != null) {
                try {
                    Claims claims = JwtUtils.parseToken(token);
                    adminId = Integer.valueOf(claims.getSubject());
                    // 这里可以根据需要从数据库获取用户名，暂时使用ID
                    adminUsername = "admin_" + adminId;
                } catch (Exception e) {
                    logger.warn("解析token失败: {}", e.getMessage());
                }
            }
        }

        // 执行目标方法
        Object result = null;
        String errorMsg = null;
        Integer status = 1; // 1-成功，0-失败

        try {
            result = joinPoint.proceed();
        } catch (Exception e) {
            status = 0;
            errorMsg = e.getMessage();
            logger.error("方法执行异常: {}", e.getMessage(), e);
            throw e;
        } finally {
            long executeTime = System.currentTimeMillis() - startTime;

            // 异步记录日志
            try {
                recordLog(joinPoint, adminLogAnnotation, request, adminId, adminUsername,
                         result, status, errorMsg, executeTime);
            } catch (Exception e) {
                logger.error("记录操作日志失败: {}", e.getMessage(), e);
            }
        }

        return result;
    }
    
    /**
     * 记录日志
     */
    private void recordLog(ProceedingJoinPoint joinPoint, AdminLog adminLogAnnotation, 
                          HttpServletRequest request, Integer adminId, String adminUsername,
                          Object result, Integer status, String errorMsg, Long executeTime) {
        try {
            String module = adminLogAnnotation.module();
            String operation = adminLogAnnotation.operation();
            String description = adminLogAnnotation.description();
            
            String method = request != null ? request.getMethod() : "";
            String url = request != null ? request.getRequestURI() : "";
            String ip = request != null ? getClientIp(request) : "";
            String userAgent = request != null ? request.getHeader("User-Agent") : "";
            
            // 获取请求参数
            String params = "";
            if (adminLogAnnotation.includeParams()) {
                Object[] args = joinPoint.getArgs();
                if (args != null && args.length > 0) {
                    try {
                        params = objectMapper.writeValueAsString(Arrays.asList(args));
                        // 限制参数长度
                        if (params.length() > 2000) {
                            params = params.substring(0, 2000) + "...";
                        }
                    } catch (Exception e) {
                        params = "参数序列化失败: " + e.getMessage();
                    }
                }
            }
            
            // 获取响应结果
            String resultStr = "";
            if (adminLogAnnotation.includeResult() && result != null) {
                try {
                    if (result instanceof Result) {
                        Result<?> res = (Result<?>) result;
                        resultStr = String.format("code:%d, msg:%s", res.getCode(), res.getMsg());
                    } else {
                        resultStr = objectMapper.writeValueAsString(result);
                    }
                    // 限制结果长度
                    if (resultStr.length() > 1000) {
                        resultStr = resultStr.substring(0, 1000) + "...";
                    }
                } catch (Exception e) {
                    resultStr = "结果序列化失败: " + e.getMessage();
                }
            }
            
            // 保存日志
            adminLogService.saveLog(adminId, adminUsername, module, operation, description,
                                   method, url, params, resultStr, status, errorMsg, 
                                   ip, userAgent, executeTime);
                                   
        } catch (Exception e) {
            logger.error("保存操作日志异常: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 从请求中获取token
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            return token.substring(7);
        }
        return null;
    }
    
    /**
     * 获取客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
